﻿using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Gmantis.Controls.Extended
{
    public class HexColorBox : TextBoxBase
    {
        // Fields
        private byte _alpha = 0xff;
        private bool _throwColorChanged = true;
        public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(HexColorBox), new PropertyMetadata(new PropertyChangedCallback(HexColorBox.OnColorPropertyChanged)));
        public static readonly DependencyProperty ShowAlphaChannelProperty = DependencyProperty.Register("ShowAlphaChannel", typeof(bool), typeof(HexColorBox), new PropertyMetadata(true, new PropertyChangedCallback(HexColorBox.OnShowAlphaChannelPropertyChanged)));
        public static readonly DependencyProperty ShowSharpPrefixProperty = DependencyProperty.Register("ShowSharpPrefix", typeof(bool), typeof(HexColorBox), new PropertyMetadata(false, new PropertyChangedCallback(HexColorBox.OnShowSharpPrefixPropertyChanged)));

        // Events
        public event EventHandler<PropertyChangedEventArgs<Color>> ColorChanged;

        // Methods
        public HexColorBox()
        {
            base.DefaultStyleKey = typeof(TextBoxBase);
        }

        private void HexColorBox_LostFocus(object sender, RoutedEventArgs e)
        {
            this.UpdateText();
        }

        private void HexColorBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            string str = base.Text.Trim().ToUpper();
            string str2 = "";
            bool flag = true;
            foreach (char ch in str.ToCharArray())
            {
                if ((((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'F'))) || (((ch == '#') && this.ShowSharpPrefix) && flag))
                {
                    str2 = str2 + ch;
                    flag = false;
                }
            }
            if (this.ShowSharpPrefix && !str2.StartsWith("#"))
            {
                str2 = "#" + str2;
            }
            int length = (this.ShowSharpPrefix ? 1 : 0) + (this.ShowAlphaChannel ? 8 : 6);
            if (str2.Length > length)
            {
                str2 = str2.Substring(0, length);
            }
            if (base.Text != str2)
            {
                int selectionStart = base.SelectionStart;
                base.Text = str2;
                base.SelectionStart = Math.Max(this.ShowSharpPrefix ? 1 : 0, Math.Min(length, selectionStart));
            }
            else if (base.Text.Length == length)
            {
                this.Color = WebColor.ToColor(base.Text, this._alpha);
            }
        }

        private static string FormatColor(Color color, bool showSharpPrefix, bool showAlphaChannel)
        {
            return ((showSharpPrefix ? "#" : "") + (showAlphaChannel ? string.Format("{0:X2}", color.A) : "") + string.Format("{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B));
        }

        private void OnAfterApplyTemplate()
        {
            this.UpdateText();
            base.TextChanged += new TextChangedEventHandler(this.HexColorBox_TextChanged);
            base.LostFocus += new RoutedEventHandler(this.HexColorBox_LostFocus);
        }

        public override void OnApplyTemplate()
        {
            string str = string.Empty;
            base.OnApplyTemplate();
            if (!string.IsNullOrEmpty(str))
            {
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to HexColorBox.\nDetails: {0}", new object[] { str }));
                }
            }
            else
            {
                this.OnAfterApplyTemplate();
            }
        }

        private void OnColorChanged(Color oldValue)
        {
            this._alpha = this.Color.A;
            this.UpdateText();
        }

        private static void OnColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HexColorBox sender = d as HexColorBox;
            Color oldValue = (Color)e.OldValue;
            sender.OnColorChanged(oldValue);
            if ((sender.ColorChanged != null) && sender._throwColorChanged)
            {
                PropertyChangedEventArgs<Color> args = new PropertyChangedEventArgs<Color>
                {
                    OldValue = (Color)e.OldValue,
                    NewValue = (Color)e.NewValue
                };
                sender.ColorChanged(sender, args);
            }
        }

        private void OnShowAlphaChannelChanged(bool oldValue)
        {
            this.UpdateText();
        }

        private static void OnShowAlphaChannelPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HexColorBox box = d as HexColorBox;
            bool oldValue = (bool)e.OldValue;
            box.OnShowAlphaChannelChanged(oldValue);
        }

        private void OnShowSharpPrefixChanged(bool oldValue)
        {
            this.UpdateText();
        }

        private static void OnShowSharpPrefixPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HexColorBox box = d as HexColorBox;
            bool oldValue = (bool)e.OldValue;
            box.OnShowSharpPrefixChanged(oldValue);
        }

        private void UpdateText()
        {
            base.Text = FormatColor(this.Color, this.ShowSharpPrefix, this.ShowAlphaChannel);
        }

        // Properties
        public Color Color
        {
            get { return (Color)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        public bool ShowAlphaChannel
        {
            get { return (bool)GetValue(ShowAlphaChannelProperty); }
            set { SetValue(ShowAlphaChannelProperty, value); }
        }

        public bool ShowSharpPrefix
        {
            get { return (bool)GetValue(ShowSharpPrefixProperty); }
            set { SetValue(ShowSharpPrefixProperty, value); }
        }
    }
}
